<template>
    <div class="zw-unity-kit-input-number">
        <el-input-number
            v-model="numberModelValue"
            :controls="false"
            :disabled="props.disabled"
            :max="maxNumber"
            :min="minNumber"
            :precision="precisionNumber"
            :placeholder="props.placeholder"
            @change="handleChange"
            @blur="handleBlur" />
        <span class="input-number-unit">
            {{ unit }}
        </span>
    </div>
</template>
<script lang="ts" setup>
import { computed, ref, getCurrentInstance, watch } from 'vue';
import { ElInputNumber } from 'element-plus';

import Decimal from 'decimal.js';

import { UNIT_ENUM, UNIT_RATIO_ENUM } from './type';

const app = getCurrentInstance();

const emit = defineEmits<{
    /**
     * 控件失去焦点之后的事件
     */
    (e: 'blur'): void;
    /**
     * v-model的绑定事件.
     */
    (e: 'update:modelValue', modelValue: number): void;
    /**
     * v-model:selected的绑定事件.
     */
    (e: 'change', currentValue: number, oldValue: number): void;
}>();

defineOptions({
    name: 'ZwUnityKitInputNumber',
    inheritAttrs: false
});

// props参数
interface IProps {
    /** v-model绑定的值 */
    modelValue?: number;
    /** 是否禁用 */
    disabled?: boolean;
    /** 金额单位，会影响到展示部分，但是v-model的值还是分为单位 */
    amountUnits?: 'YUAN' | 'WAN_YUAN';
    /** amount：金额, rate: 费率 */
    type?: 'amount' | 'rate';
    /** 输入框占用文本 */
    placeholder?: string;
    // 下面三个先放上，type会设置默认的最小值和最大值以及小数点精度
    /** 数字最小值 */
    min?: number;
    /** 数字最大值 */
    max?: number;
    /** 小数点精度 */
    precision?: number;
}

const props = withDefaults(defineProps<IProps>(), {
    modelValue: undefined,
    /** 是否禁用 */
    disabled: false,
    type: 'amount',
    amountUnits: 'WAN_YUAN',
    placeholder: '请输入',
    // 下面三个先放上，type会设置默认的最小值和最大值以及小数点精度
    /** 数字最小值 */
    min: 0,
    /** 数字最大值 */
    max: Infinity,
    /** 小数点精度 */
    precision: 4
});

/* ----------------------------输入框控件配置-start---------------------------- */
/**
 * 根据类型的不同策略配置
 */
const numberTypeStrategy = {
    amount: {
        max: 99999999999.9999,
        min: 0,
        precision: 4
    },
    rate: {
        max: 1,
        min: 0.21,
        precision: 2
    }
};

/**
 * 数字的单位
 */
const unit = computed(() => {
    if (props.type === 'amount') {
        return UNIT_ENUM[props.amountUnits];
    }
    return UNIT_ENUM.RATE;
});

/**
 * 最大值
 */
const maxNumber = computed(() => {
    return numberTypeStrategy[props.type]?.max || props.max;
});

/**
 * 最小值
 */
const minNumber = computed(() => {
    return numberTypeStrategy[props.type]?.min || props.min;
});

/**
 * 精度
 */
const precisionNumber = computed(() => {
    return numberTypeStrategy[props.type]?.precision || props.precision;
});
/* ----------------------------输入框控件配置-end---------------------------- */

/* ----------------------------数值绑定倍率计算-start---------------------------- */
/**
 * 获取当前数值的倍率
 */
const currentUnitRatio = computed(() => {
    if (props.type === 'amount') {
        return UNIT_RATIO_ENUM[props.amountUnits];
    }
    return UNIT_RATIO_ENUM.RATE;
});

/**
 * 通过以下watch的方式来实现功能
 * 这样的方式看着是不太舒服、
 * 但是ts的校验针对计算属性的get值校验太严格了。
 */
/**
 * 数字绑定的值
 */
const numberModelValue = ref();

/**
 * 通过watch监听变化实时变更v-model的值
 */
watch(numberModelValue, (val: number) => {
    if (val || val === 0) {
        emit('update:modelValue', Number(Decimal.mul(val, currentUnitRatio.value)));
    } else {
        emit('update:modelValue', undefined);
    }
});

/**
 * 外部的props如果发生了变化，内部则进行一次转换处理
 */
watch(
    () => props.modelValue,
    (val: number) => {
        if (Number.isNaN(Number(val))) {
            numberModelValue.value = undefined;
            return;
        }

        if (val || val === 0) {
            numberModelValue.value = Number(Decimal.div(val, currentUnitRatio.value));
        } else {
            numberModelValue.value = undefined;
        }
    },
    {
        immediate: true
    }
);
/* ----------------------------数值绑定倍率计算-end---------------------------- */

/** 限制长度16个字符 */
// const MAX_LENGTH = 16;
const handleChange = (currentValue: number, oldValue: number) => {
    // 限制长度16个字符
    // const [value] = arg;
    // const valueStr = new Decimal(value).toFixed(precisionNumber.value, Decimal.ROUND_DOWN);
    // if (valueStr.length > MAX_LENGTH) {
    //     // 截取整数部分到MAX_LENGTH+1位
    //     const [intNumber, floatNumber] = valueStr.split('.');
    //     const newIntValue = intNumber.substring(0, MAX_LENGTH - (precisionNumber.value + 1));
    //     const newValue = `${newIntValue}.${floatNumber}`;
    //     emit('update:modelValue', Decimal.mul(Number.parseFloat(newValue), currentUnitRatio.value));
    //     return;
    // }
    emit('change', currentValue, oldValue);
};

const handleBlur = (...arg) => {
    emit('blur', ...arg);
};
</script>

<style lang="scss" scoped>
@import './Index';
</style>
